﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IMLibrary;
using Lidgren.Network; 
using System.Threading;

namespace IMLibrary.Server
{
    /// <summary>
    /// UDP高效能处理服务器
    /// </summary>
    public class UDPServer
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        public UDPServer()
        {

        }

        #region 属性
        /// <summary>
        /// 
        /// </summary>
        private Lidgren.Network.NetServer s_server = null;
        /// <summary>
        /// UDP服务线程
        /// </summary>
        private System.Threading.Thread thUdpServer = null;

        private bool Run = true;

        /// <summary>
        /// 服务器支持最大连接数
        /// </summary>
        public int MaxConnections
        {
            set;
            get;
        }
        #endregion

        #region 事件

        public delegate void EventHandler(object sender, UDPEventArgs e);
        /// <summary>
        /// 客户端已联接事件
        /// </summary>
        public event EventHandler Connected;
        private void onConnected(UDPEventArgs e)
        {
            if (Connected != null)
                Connected(this, e);

        }
        /// <summary>
        /// 客户端联接断开事件
        /// </summary>
        public event EventHandler Disconnected;
        private void onDisconnected(UDPEventArgs e)
        {
            if (Disconnected != null)
                Disconnected(this, e);

        }
        /// <summary>
        /// 收到消息事件
        /// </summary>
        public event EventHandler RecivedMsg;
        private void onRecivedMsg(UDPEventArgs e)
        {
            if (RecivedMsg != null)
                RecivedMsg(this, e);
        }

        /// <summary>
        /// 收到未知消息事件
        /// </summary>
        public event EventHandler RecivedElseData;
        private void onRecivedElseData(UDPEventArgs e)
        {
            if (RecivedElseData != null)
                RecivedElseData(this, e);
        }
        /// <summary>
        /// 收到系统消息（警告、调试、错误等）事件
        /// </summary>
        public event EventHandler RecivedSystemMsg;
        private void onRecivedSystemMsg(UDPEventArgs e)
        {
            if (RecivedSystemMsg != null)
                RecivedSystemMsg(this, e);
        }
        #endregion

        #region 公共方法
        /// <summary>
        /// 安装网络服务
        /// </summary>
        public void Start(int Port = 14242)
        {
            if (s_server == null)
            {
                NetPeerConfiguration config = new NetPeerConfiguration("OurMsg");
                config.MaximumConnections = 10000;// MaxConnections;
                config.Port = Port;
                config.PingInterval = 20.0f;
                config.ReceiveBufferSize = 1024 * 10000;
                config.SendBufferSize  = 1024 * 10000;
                s_server = new Lidgren.Network.NetServer(config);
            }
            s_server.Start();
            s_server.StratAuthenticate();


            thUdpServer = new Thread(GotMessage);
            thUdpServer.Start(null);
        }

        /// <summary>
        /// 获得服务端口
        /// </summary>
        /// <returns></returns>
        public int GetServerPort()
        {
            if (s_server != null)
                return s_server.Port;
            else
                return 0;
        }

        /// <summary>
        /// 停止服务
        /// </summary>
        public void Stop()
        {
            if (s_server != null)
            {
                s_server.StopAuthenticate();
                s_server.Shutdown("The server shutdown!");
            }
            if (thUdpServer != null)
                thUdpServer.Abort();
        }

        /// <summary>
        /// 广播消息
        /// </summary>
        /// <param name="data"></param>
        /// <param name="from"></param>
        public void Broadcast(byte[] data, NetConnection from)
        {
            List<NetConnection> all = s_server.Connections;
            if (from != null)
                all.Remove(from);// 删除消息发送者
            if (all.Count > 0)
            {
                NetOutgoingMessage om = s_server.CreateMessage();
                om.Write(data);
                s_server.SendMessage(om, all, NetDeliveryMethod.ReliableOrdered, 0);
            }
        }

        /// <summary>
        /// 广播消息
        /// </summary>
        /// <param name="data">消息</param>
        /// <param name="from">消息发送者(值为NULL表示发送给所有客户端，否则消息不发送给发送客户端)</param>
        public void Broadcast(string data, NetConnection from)
        {
            Broadcast(Encoding.UTF8.GetBytes(data), from);
        }

        /// <summary>
        /// 发送消息到一组客户端
        /// </summary>
        /// <param name="data">消息</param>
        /// <param name="tos">消息接收者</param>
        public void Send(byte[] data, List<NetConnection> tos)
        {
            NetOutgoingMessage om = s_server.CreateMessage();
            om.Write(data);
            s_server.SendMessage(om, tos, NetDeliveryMethod.ReliableOrdered, 0);
        }

        /// <summary>
        /// 发送消息到一组客户端
        /// </summary>
        /// <param name="data">消息</param>
        /// <param name="tos">消息接收者</param>
        public void Send(string data, List<NetConnection> tos)
        {
            Send(Encoding.UTF8.GetBytes(data), tos);
        }

        /// <summary>
        /// 发送消息到一个客户端
        /// </summary>
        /// <param name="data">消息</param>
        /// <param name="to">消息接收者</param>
        public void Send(byte[] data, NetConnection to)
        {
            NetOutgoingMessage om = s_server.CreateMessage();
            om.Write(data);
            s_server.SendMessage(om, to, NetDeliveryMethod.ReliableOrdered, 0);
        }

        /// <summary>
        /// 发送消息到一个客户端
        /// </summary>
        /// <param name="data">消息</param>
        /// <param name="to">消息接收者</param>
        public void Send(string data, NetConnection to)
        {
            Send(Encoding.UTF8.GetBytes(data), to);
        }

        /// <summary>
        /// 清除联接
        /// </summary>
        public void ClearSessions()
        {
            if (s_server != null)
                foreach (var se in s_server.Connections)
                {
                    try
                    {
                        se.Disconnect("");
                    }
                    catch { }
                }
        }
        #endregion


        #region 私有方法
        private void GotMessage(object obj)
        {
            while (Run)
            {
                NetIncomingMessage im;
                while ((im = s_server.ReadMessage()) != null)
                {
                    switch (im.MessageType)
                    {
                        case NetIncomingMessageType.DebugMessage:
                        case NetIncomingMessageType.ErrorMessage:
                        case NetIncomingMessageType.WarningMessage:
                        case NetIncomingMessageType.VerboseDebugMessage:
                            onRecivedSystemMsg(new UDPEventArgs(false, new byte[0], im.SenderConnection));
                            break;
                        case NetIncomingMessageType.StatusChanged:
                            NetConnectionStatus status = (NetConnectionStatus)im.ReadByte();
                            if (status == NetConnectionStatus.Disconnected)
                                onDisconnected(new UDPEventArgs(false, null, im.SenderConnection));
                            else if (status == NetConnectionStatus.Connected)
                            {
                                im.SenderConnection.ConnectTime = DateTime.Now;
                                onConnected(new UDPEventArgs(false, null, im.SenderConnection));
                            }
                            break;
                        case NetIncomingMessageType.Data:
                            onRecivedMsg(new UDPEventArgs(false, im.ReadBytes(im.LengthBytes), im.SenderConnection));
                            break;
                        default:
                            onRecivedElseData(new UDPEventArgs(false, im.ReadBytes(im.LengthBytes), im.SenderConnection));
                            break;
                    }
                }
                System.Threading.Thread.Sleep(1);
            }
        }
        #region 不用
        //private void Application_Idle(object sender, EventArgs e)
        //{
        //    while (IM.Base.NativeMethods.AppStillIdle)
        //    {

        //        NetIncomingMessage im;
        //        while ((im = s_server.ReadMessage()) != null)
        //        {
        //            switch (im.MessageType)
        //            {
        //                case NetIncomingMessageType.DebugMessage:
        //                case NetIncomingMessageType.ErrorMessage:
        //                case NetIncomingMessageType.WarningMessage:
        //                case NetIncomingMessageType.VerboseDebugMessage:
        //                    onRecivedSystemMsg(new UDPServerEventArgs(false, new byte[0], im.SenderConnection));
        //                    break;
        //                case NetIncomingMessageType.StatusChanged:
        //                    NetConnectionStatus status = (NetConnectionStatus)im.ReadByte();
        //                    if (status == NetConnectionStatus.Disconnected)
        //                        onDisconnected(new UDPServerEventArgs(false, null, im.SenderConnection));
        //                    else if (status == NetConnectionStatus.Connected)
        //                        onConnected(new UDPServerEventArgs(false, null, im.SenderConnection));
        //                    break;
        //                case NetIncomingMessageType.Data:
        //                    onRecivedMsg(new UDPServerEventArgs(false, im.ReadBytes(im.LengthBytes), im.SenderConnection));
        //                    break;
        //                default:
        //                    onRecivedElseData(new UDPServerEventArgs(false, im.ReadBytes(im.LengthBytes), im.SenderConnection));
        //                    break;
        //            }
        //        } 
        //    }
        //}
        #endregion
        #endregion

    }
}
